﻿using Microsoft.Practices.Unity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.ServiceModel;
using System.Text;
using System.Web;

namespace YiDa.Infrastructure
{
    /// <summary>
    /// 容器类
    /// </summary>
    class ContainerExtension : IExtension<OperationContext>
    {
        public ContainerExtension()
        {

        }

        public object Value { get; set; }        

        #region IExtension<OperationContext> Members

        public void Attach(OperationContext owner)
        {

        }

        public void Detach(OperationContext owner)
        {

        }

        #endregion
    }

    /// <summary>
    /// 在Service的Web.config中有使用，用来控制实例化对象的行为，这个类的目的是实现使用该LifetimeManager注册的类型在每个Request期间只有一个实例
    /// RepositoryContext(Unit of Work)正是整个Request只有一个实例的需求
    /// http://msdn.microsoft.com/en-us/library/ff660872%28v=pandp.20%29.aspx  Understanding Lifetime Managers
    /// </summary>
    public class PerRequestLifetimeManager : LifetimeManager
    {        
        private readonly Guid key = Guid.NewGuid();        

        public PerRequestLifetimeManager() : this(Guid.NewGuid()) 
        { 
        }

        PerRequestLifetimeManager(Guid key)
        {
            if (key == Guid.Empty)
            {
                throw new ArgumentException("Key is empty.");
            }

            this.key = key;
        }

        /// <summary>
        /// 存储对象
        /// </summary>
        /// <remarks>
        /// ContainerExtension：用于未启未启用HttpContext的WCF环境；
        /// HttpContext：用于WCF、Asp.net等环境
        /// CallContext：用于非WCF、Asp.net等环境，可能是单元测试, WinForms, WPF等
        /// </remarks>
        public override void SetValue(object newValue)
        {
            if (OperationContext.Current != null)
            {
                //未启用HttpContext的WCF环境
                //http://stackoverflow.com/questions/7373623/my-first-wcf-server-why-operationcontext-current-is-null
                //上文说，OperationContext.Current是在每次Reqest请求时创建的，但是只有在调用WCF服务时才会被初始化
                //ContainerExtension的实例在此被创建的。而containerExtension.Value是在Web.config配置的EntityFrameworkRepositoryContext
                //为什么使用Extensions？原因其实就是为了存储一些与当前上下文相关的一些对象的一种方式，WCF推荐用这种方式，因为WCF没有HttpContext。参考：http://blog.caraulean.com/2008/02/13/httpcontext-idiom-for-windows-communication-foundation/  http://msdn.microsoft.com/en-us/library/ms733816.aspx

                ContainerExtension containerExtension = OperationContext.Current.Extensions.Find<ContainerExtension>();
                if (containerExtension == null)
                {
                    containerExtension = new ContainerExtension()
                    {
                        Value = newValue
                    };

                    OperationContext.Current.Extensions.Add(containerExtension);
                }
            }
            else if (HttpContext.Current != null)
            {            
                if (HttpContext.Current.Items[key.ToString()] == null)
                {
                    HttpContext.Current.Items[key.ToString()] = newValue;
                }
            }
            else
            {                
                CallContext.SetData(key.ToString(), newValue);
            }
        }


        /// <summary>
        /// 获取此生命周期策略的对象
        /// </summary>
        /// <returns></returns>
        public override object GetValue()
        {
            object result = null;

            if (OperationContext.Current != null)
            {
                ContainerExtension containerExtension = OperationContext.Current.Extensions.Find<ContainerExtension>();
                if (containerExtension != null)
                {
                    result = containerExtension.Value;
                }
            }
            else if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items[key.ToString()] != null)
                {
                    result = HttpContext.Current.Items[key.ToString()];
                }
            }
            else
            {                
                result = CallContext.GetData(key.ToString());
            }

            return result;
        }
        /// <summary>
        /// 移除对象
        /// </summary>
        public override void RemoveValue()
        {
            if (OperationContext.Current != null)
            {                
                ContainerExtension containerExtension = OperationContext.Current.Extensions.Find<ContainerExtension>();
                if (containerExtension != null)
                {
                    object obj = containerExtension.Value;
                    if (obj is IDisposable)
                    {
                        (obj as IDisposable).Dispose();
                    }
                    OperationContext.Current.Extensions.Remove(containerExtension);
                }

            }
            else if (HttpContext.Current != null)
            {
                if (HttpContext.Current.Items[key.ToString()] != null)
                {
                    if (HttpContext.Current.Items[key.ToString()] is IDisposable)
                    {
                        (HttpContext.Current.Items[key.ToString()] as IDisposable).Dispose();
                    }
                    HttpContext.Current.Items[key.ToString()] = null;
                }
            }
            else
            {                
                CallContext.FreeNamedDataSlot(key.ToString());
            }
        }        
    }
}
